interface MethodsBindEvts {
  [k: string]: {
    eventName: string;
    callBack: (...params: any[]) => void;
  }[];
}
export class ModeEvent {
  protected modName: string;
  protected mod: any;
  private currentMethod: string;
  private eventStore: WeakMap<Function, string[]>;
  private methodsBindEvts: MethodsBindEvts;
  constructor(modName: string, mod: any) {
    this.mod = mod;
    this.modName = modName;
    this.currentMethod = "";
    this.eventStore = new WeakMap();
    this.methodsBindEvts = {};
  }
  protected setCurrentMethod(methodName: string) {
    this.currentMethod = methodName;
  }
  protected setMethodEvent(eventName: string, callBack: (...params: any[]) => void) {
    if (Array.isArray(this.methodsBindEvts[this.currentMethod])) {
      this.methodsBindEvts[this.currentMethod].push({
        eventName,
        callBack,
      });
    } else {
      this.methodsBindEvts[this.currentMethod] = [];
      this.setMethodEvent(eventName, callBack);
    }
  }
  protected add(eventName: string, callBack: (...params: any[]) => void) {
    let val = this.eventStore.get(callBack);
    if (val === undefined) {
      this.eventStore.set(callBack, []);
      this.add(eventName, callBack);
    } else {
      if (!val.includes(eventName)) {
        val.push(eventName);
        this.setMethodEvent(eventName, callBack);
        this.eventStore.set(callBack, val);
        this.mod[eventName].connect(callBack);
      }
    }
    // if (!this.eventStore.has(callBack)) {
    //   this.setMethodEvent(eventName, callBack);
    //   this.eventStore.set(callBack, eventName);
    //   this.mod[eventName].connect(callBack);
    // }
  }
  protected remove(eventName: string, callBack: (...params: any[]) => void) {
    let val = this.eventStore.get(callBack);
    if (val !== undefined) {
      let idx = val.indexOf(eventName);
      if (idx >= 0) {
        val.splice(idx, 1);
        setTimeout(() => {
          this.mod[eventName].disconnect(callBack);
        }, 0)
      }
      if (val.length === 0) {
        this.eventStore.delete(callBack);
      }
    }

    // if (this.eventStore.has(callBack)) {
    //   this.eventStore.delete(callBack);
    //   this.mod[eventName].disconnect(callBack);
    // }
  }
  protected removeMethodBindEvt(methodName: string) {
    let recordEvts = this.methodsBindEvts[methodName];
    if (recordEvts) {
      recordEvts.forEach((value) => {
        this.remove(value.eventName, value.callBack);
      });
      delete this.methodsBindEvts[this.currentMethod];
    }
  }
}
